'''
Version: 1.0
Author: hpf
Date: 2021-05-28 01:44:14
LastEditTime: 2021-07-30 03:00:13
LastEditors: hpf
Description: gRPC通信逻辑主体以及任务处理主体
FilePath: /trackrunner/grpcclient/grpcclient.py
'''
import configparser
import os
import subprocess
import sys
import threading
import time
from threading import Thread

import grpc

sys.path.append("./grpcclient")
import ServiceTask_pb2, ServiceTask_pb2_grpc

SERVER_ADDRESS = "localhost:6061"
RESULT_PATH = "/data/result"

TASK_LIST = []
REQUEST_LIST = []
TASK_MUTEX = threading.Lock()
REQUEST_MUTEX = threading.Lock()
'''
@description: 开启gRPC，双向流模式 (在一次调用中, 客户端和服务器都可以向对方多次收发数据)
@param {*} stub 
@return {*}
'''


def start_grpc_streaming(stub):
    print("--------------Start gRPC---------------")

    # 创建一个消息生成
    def request_messages():
        yield ServiceTask_pb2.Message(
            request_type=ServiceTask_pb2.REQUESTTYPE_REQUEST,
            message_type=ServiceTask_pb2.MESSAGETYPE_REGISTRY,
            job_type=ServiceTask_pb2.JOB_ALL)
        while True:
            REQUEST_MUTEX.acquire()
            if len(REQUEST_LIST) > 0:
                request = REQUEST_LIST[0]
                REQUEST_LIST.pop(0)
                REQUEST_MUTEX.release()
                yield request
            else:
                REQUEST_MUTEX.release()
                time.sleep(0.01)

    # 接收消息
    response_iterator = stub.Start(request_messages())
    for response in response_iterator:
        TASK_MUTEX.acquire()
        TASK_LIST.append(response)
        TASK_MUTEX.release()
        print("recv from server(%d), message=%s" % (response.request_id,
                                                    response.request_type))


'''
@description: 任务处理线程
@param {*}
@return {*}
'''


def start_process():
    # 循环处理任务
    while True:
        TASK_MUTEX.acquire()
        # 队列不为空，则进行处理
        if len(TASK_LIST) > 0:
            runningtask = TASK_LIST[0]
            TASK_LIST.pop(0)
            TASK_MUTEX.release()
            output_path = os.path.join(RESULT_PATH,
                                       str(runningtask.algorithm_job.job_id))
            if not os.path.exists(output_path):
                os.makedirs(output_path)
            print(
                "----------------------recv task from server---------------------"
            )
            ''' print("job type: ", runningtask.job_type)
            print("data type: ", runningtask.algorithm_job.data_type)
            print("library path: ",
                  runningtask.algorithm_job.algorithm_info.library_path)
            print("model path: ",
                  runningtask.algorithm_job.algorithm_info.model_path)
            print("config path: ",
                  runningtask.algorithm_job.algorithm_info.config_path)
            print("data input dir:", runningtask.algorithm_job.process_path) '''
            # 任务类型为视频类型
            if runningtask.algorithm_job.data_type == ServiceTask_pb2.DATATYPE_VIDEO:
                # 为进程启动添加参数
                cmd_list = []
                cmd_list.append("python")
                cmd_list.append("-u")
                if runningtask.job_type == ServiceTask_pb2.JOB_SUPERRESOLUTION:
                    cmd_list.append("superrunner.py")
                elif runningtask.job_type == ServiceTask_pb2.JOB_OBJECTDETECTION:
                    cmd_list.append("detectrunner.py")
                elif runningtask.job_type == ServiceTask_pb2.JOB_OBJECTTRACK:
                    cmd_list.append("trackrunner.py")
                elif runningtask.job_type == ServiceTask_pb2.JOB_REID:
                    cmd_list.append("reidrunner.py")
                    cmd_list.append(
                        runningtask.algorithm_job.search_image_path)
                elif runningtask.job_type == ServiceTask_pb2.JOB_ACTIONRECOGNITION:
                    cmd_list.append("actionrunner.py")
                else:
                    continue
                cmd_list.append(
                    runningtask.algorithm_job.algorithm_info.library_path)
                cmd_list.append(
                    runningtask.algorithm_job.algorithm_info.model_path)
                cmd_list.append(
                    runningtask.algorithm_job.algorithm_info.config_path)
                cmd_list.append(
                    runningtask.algorithm_job.process_path)  #video file path
                cmd_list.append(output_path)
                cmd_list.append("0")
                # 启动进程
                p = subprocess.Popen(
                    cmd_list,
                    shell=False,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.STDOUT)
                while p.poll() is None:  # 这里死循环了.
                    line = p.stdout.readline()  # readlines(100)
                    line = line.strip()
                    if line:
                        line_str = str(line, encoding="utf-8")
                        # 返回处理进度
                        if line_str.find("PlatformProcessNum") >= 0:
                            line_list = line_str.split(":")
                            process_num = int(line_list[1])
                            request = ServiceTask_pb2.Message(
                                request_id=0,
                                request_type=ServiceTask_pb2.
                                REQUESTTYPE_REQUEST,
                                error_code=ServiceTask_pb2.ERRORCODE_SUCCESS,
                                message_type=ServiceTask_pb2.
                                MESSAGETYPE_REPORT_JOB,
                                job_type=runningtask.job_type,
                                algorithm_process=ServiceTask_pb2.
                                AlgorithmProcess(
                                    job_id=runningtask.algorithm_job.job_id,
                                    process=process_num))
                            REQUEST_MUTEX.acquire()
                            REQUEST_LIST.append(request)
                            REQUEST_MUTEX.release()
                        else:
                            print(line_str)
                if p.returncode == 0:
                    print('Subprogram success')
                else:
                    print('Subprogram failed')
                    # 返回处理结果
                result_request = ServiceTask_pb2.Message(
                    request_id=0,
                    request_type=ServiceTask_pb2.REQUESTTYPE_REQUEST,
                    error_code=ServiceTask_pb2.ERRORCODE_SUCCESS,
                    message_type=ServiceTask_pb2.MESSAGETYPE_REPORT_RESULT,
                    job_type=runningtask.job_type,
                    algorithm_result=ServiceTask_pb2.AlgorithmResult(
                        job_id=runningtask.algorithm_job.job_id,
                        result_path=output_path))
                print(result_request)
                REQUEST_MUTEX.acquire()
                REQUEST_LIST.append(result_request)
                REQUEST_MUTEX.release()
            # 任务类型为数据集类型
            elif runningtask.algorithm_job.data_type == ServiceTask_pb2.DATATYPE_DATASET:
                # 为进程启动添加参数
                cmd_list = []
                cmd_list.append("python")
                cmd_list.append("-u")
                if runningtask.job_type == ServiceTask_pb2.JOB_SUPERRESOLUTION:
                    cmd_list.append("superrunner.py")
                elif runningtask.job_type == ServiceTask_pb2.JOB_OBJECTDETECTION:
                    cmd_list.append("detectrunner.py")
                elif runningtask.job_type == ServiceTask_pb2.JOB_OBJECTTRACK:
                    cmd_list.append("trackrunner.py")
                elif runningtask.job_type == ServiceTask_pb2.JOB_REID:
                    cmd_list.append("reidrunner.py")
                    cmd_list.append(runningtask.algorithm_job.search_image_path
                                    )  #reid query image
                elif runningtask.job_type == ServiceTask_pb2.JOB_ACTIONRECOGNITION:
                    cmd_list.append("actionrunner.py")
                else:
                    print("so sorry.")
                    continue
                cmd_list.append(
                    runningtask.algorithm_job.algorithm_info.library_path)
                cmd_list.append(
                    runningtask.algorithm_job.algorithm_info.model_path)
                cmd_list.append(
                    runningtask.algorithm_job.algorithm_info.config_path)
                cmd_list.append(
                    runningtask.algorithm_job.process_path)  #dataset dir
                cmd_list.append(output_path)
                cmd_list.append("1")
                # 启动进程
                p = subprocess.Popen(
                    cmd_list,
                    shell=False,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.STDOUT)
                while p.poll() is None:  # 这里死循环了.
                    line = p.stdout.readline()  # readlines(100)
                    line = line.strip()
                    if line:
                        line_str = str(line, encoding="utf-8")
                        if line_str.find("PlatformProcessNum") >= 0:
                            # 返回处理进度
                            line_list = line_str.split(":")
                            process_num = int(line_list[1])
                            request = ServiceTask_pb2.Message(
                                request_id=0,
                                request_type=ServiceTask_pb2.
                                REQUESTTYPE_REQUEST,
                                error_code=ServiceTask_pb2.ERRORCODE_SUCCESS,
                                message_type=ServiceTask_pb2.
                                MESSAGETYPE_REPORT_JOB,
                                job_type=runningtask.job_type,
                                algorithm_process=ServiceTask_pb2.
                                AlgorithmProcess(
                                    job_id=runningtask.algorithm_job.job_id,
                                    process=process_num))
                            REQUEST_MUTEX.acquire()
                            REQUEST_LIST.append(request)
                            REQUEST_MUTEX.release()
                        elif line_str.find("PlatformSummary") >= 0:
                            # 返回处理结果
                            line_list = line_str.split("PlatformSummary:")
                            process_num = line_list[1]

                            result_request = ServiceTask_pb2.Message(
                                request_id=0,
                                request_type=ServiceTask_pb2.
                                REQUESTTYPE_REQUEST,
                                error_code=ServiceTask_pb2.ERRORCODE_SUCCESS,
                                message_type=ServiceTask_pb2.
                                MESSAGETYPE_REPORT_RESULT,
                                job_type=runningtask.job_type,
                                algorithm_result=ServiceTask_pb2.
                                AlgorithmResult(
                                    job_id=runningtask.algorithm_job.job_id,
                                    result_path=output_path,
                                    result_statistics=process_num))
                            REQUEST_MUTEX.acquire()
                            REQUEST_LIST.append(result_request)
                            REQUEST_MUTEX.release()
                        else:
                            print(line_str)
                if p.returncode == 0:
                    print('Subprogram success')
                else:
                    print('Subprogram failed')
        else:
            TASK_MUTEX.release()
            time.sleep(1)


def rungrpc():
    # 开启处理线程
    t = Thread(target=start_process)
    t.start()

    # 加载配置文件
    root_dir = os.path.abspath('.')
    config = configparser.ConfigParser()
    config.read(root_dir + "/config.ini")
    if config.has_option("config", "ServerAddress"):
        global SERVER_ADDRESS
        SERVER_ADDRESS = config.get("config", "ServerAddress")
    if config.has_option("config", "ResultPath"):
        global RESULT_PATH
        RESULT_PATH = config.get("config", "ResultPath")

    # 开启gRPC服务，死循环，断开重连
    while True:
        try:
            print("connecting to grpc server:", SERVER_ADDRESS)
            with grpc.insecure_channel(SERVER_ADDRESS) as channel:
                stub = ServiceTask_pb2_grpc.ServiceTaskStub(channel)
                start_grpc_streaming(stub)
            time.sleep(0.1)
        except KeyboardInterrupt:
            os._exit(0)
        except:
            print("--------------End gRPC---------------")
            time.sleep(1)


if __name__ == '__main__':
    rungrpc()
